package edu.pw.p2pclient.data;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class Node implements Serializable {
	private static final long serialVersionUID = -3870627775284188812L;

	public static final int FOLDER = 0;
	public static final int FILE = 1;
	public static final int MOVE_UP = 2;

	private final static DecimalFormat FORMATTER = new DecimalFormat("#.00");

	protected String mName;
	protected String mParentPath;
	protected int mType;
	protected long mSize;
	private String mCrc;
	protected boolean mSelected;
	protected SharingInfo mSharingInfo;

	public class SharingInfo implements Serializable {
		private static final long serialVersionUID = 2180438945115952940L;

		private boolean mBtShared;
		private boolean mWifiShared;
		private boolean mPush;
		private boolean mPasswordProtected;
		protected String mPassword;

		public SharingInfo() {
			this(false, false, false, "");
		}

		public SharingInfo(boolean btShared, boolean wifiShared, boolean push) {
			this(btShared, wifiShared, push, "");
		}

		public SharingInfo(boolean btShared, boolean wifiShared, boolean push,
				String password) {
			mBtShared = btShared;
			mWifiShared = wifiShared;
			mPush = push;
			mPasswordProtected = !password.equals("");
			mPassword = password;
		}

		public SharingInfo(SharingInfo info) {
			mBtShared = info.mBtShared;
			mWifiShared = info.mWifiShared;
			mPush = info.mPush;
			mPasswordProtected = info.mPasswordProtected;
			mPassword = info.mPassword;

		}

		@Override
		public int hashCode() {
			return (mBtShared ? 1 : 0) + (mWifiShared ? 1 : 0)
					+ (mPush ? 1 : 0) + mPassword.hashCode();
		}

		public boolean isBtShared() {
			return mBtShared;
		}

		public void setBtShared(boolean btShared) {
			this.mBtShared = btShared;
		}

		public boolean isWifiShared() {
			return mWifiShared;
		}

		public void setWifiShared(boolean wifiShared) {
			this.mWifiShared = wifiShared;
		}

		public boolean isShared() {
			return mBtShared || mWifiShared || mPush;
		}

		public void setPush(boolean push) {
			mPush = push;
		}

		public boolean isPush() {
			return mPush;
		}

		public void setPasswordProtected(boolean passwordProtected) {
			mPasswordProtected = passwordProtected;
		}

		public boolean isPasswordProtected() {
			return mPasswordProtected;
		}

		public String getPassword() {
			return mPassword;
		}

		public void setPassword(String password) {
			this.mPassword = password;
		}

	}

	public Node(String path, int type) {
		int pos = path.lastIndexOf("/");
		mName = path.substring(pos + 1);
		if (pos == 0)
			pos = 1;
		if (mName.equals("")) {
			mName = "";
			mParentPath = "/";
		} else
			mParentPath = path.substring(0, pos);
		mType = type;
		mSize = 0;
		mCrc = "";
		mSelected = false;
		mSharingInfo = new SharingInfo();
	}

	public Node(File file) {
		init(file);
		mSharingInfo = new SharingInfo();
	}

	public Node(File file, SharingInfo sharingInfo) {
		init(file);
		if (sharingInfo == null)
			mSharingInfo = new SharingInfo();
		else
			mSharingInfo = sharingInfo;
	}

	public Node(File file, boolean btShared, boolean wifiShared, boolean push) {
		init(file);
		mSharingInfo = new SharingInfo(btShared, wifiShared, push);
	}

	protected Node(Node node) {
		mName = node.mName;
		mParentPath = node.mParentPath;
		if ("".equals(mParentPath))
			mParentPath = TreeNode.ROOT_PATH;
		mType = node.mType;
		mSize = node.mSize;
		mCrc = node.mCrc;
		mSelected = node.mSelected;
		mSharingInfo = new SharingInfo(node.mSharingInfo);
	}

	private void init(File file) {
		mName = file.getName();
		mParentPath = file.getParent() == null ? TreeNode.ROOT_PATH : file
				.getParent();
		mType = file.isFile() ? FILE : FOLDER;
		mSize = mType == FILE ? file.length() : 0;
		mCrc = "";
		mSelected = false;
	}

	@Override
	public boolean equals(Object o) {
		if (o == null || (!(o instanceof Resource) && !(o instanceof Node)))
			return false;
		return getFullPath().equals(((Node) o).getFullPath());
	}

	@Override
	public int hashCode() {
		return mParentPath.hashCode() + mSharingInfo.hashCode();
	}

	public String getName() {
		return (isMoveUp() ? ".." : mName);
	}

	public String getPath() {
		return mParentPath;
	}

	public boolean isFile() {
		return mType == FILE;
	}

	public boolean isShared() {
		return mSharingInfo.isShared();
	}

	public long getLongSize() {
		return mSize;
	}

	public String getCrc() {
		return mCrc;
	}

	public String getSize() {
		if (mSize == 0)
			return "0 KB";
		if (mSize >= 1048576)
			return String.valueOf(FORMATTER.format(mSize / 1048576.0)) + " MB";
		else if (mSize >= 1024)
			return String.valueOf(FORMATTER.format(mSize / 1024.0)) + " KB";
		else
			return String.valueOf(FORMATTER.format(mSize)) + " B";
	}

	public boolean isPush() {
		return mSharingInfo.isPush();
	}

	public boolean isMoveUp() {
		return mType == MOVE_UP;
	}

	public boolean isBtShared() {
		return mSharingInfo.isBtShared();
	}

	public boolean isWifiShared() {
		return mSharingInfo.isWifiShared();
	}

	public boolean isSelected() {
		return mSelected;
	}

	public SharingInfo getSharingInfo() {
		return mSharingInfo;
	}

	public void setSharingInfo(boolean btShared, boolean wifiShared,
			boolean push, String pass) {
		mSharingInfo.mBtShared = btShared;
		mSharingInfo.mWifiShared = wifiShared;
		mSharingInfo.mPush = push;
		mSharingInfo.mPasswordProtected = !"".equals(pass);
		mSharingInfo.mPassword = pass;
	}

	public void setSharingInfo(SharingInfo sharingInfo) {
		mSharingInfo = sharingInfo;
	}

	public void setSelected(boolean selected) {
		mSelected = selected;
	}

	public void calcCrc() {
		if (!mCrc.equals(""))
			return;

		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			FileInputStream fis = new FileInputStream(getFullPath());

			byte[] dataBytes = new byte[1024];

			int nread = 0;
			while ((nread = fis.read(dataBytes)) != -1) {
				md.update(dataBytes, 0, nread);
			}
			fis.close();
			byte[] mdbytes = md.digest();

			StringBuffer hexString = new StringBuffer();
			for (int i = 0; i < mdbytes.length; i++) {
				String hex = Integer.toHexString(0xff & mdbytes[i]);
				if (hex.length() == 1)
					hexString.append('0');
				hexString.append(hex);
			}
			mCrc = hexString.toString();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public String getFullPath() {
		if (!mParentPath.startsWith("/"))
			mParentPath = "/" + mParentPath;
		if (mParentPath.endsWith("/"))
			return mParentPath + mName;
		return mParentPath + "/" + mName;
	}

	public final static JsonSerializer<Node> serializer = new JsonSerializer<Node>() {

		@Override
		public JsonElement serialize(Node arg0, Type arg1,
				JsonSerializationContext arg2) {

			JsonObject elem = new JsonObject();
			elem.addProperty("name", arg0.mName);
			elem.addProperty("size", arg0.mSize);
			elem.addProperty("crc", arg0.getCrc());
			return elem;
		}

	};

	public void resetSharingInfo() {
		setSharingInfo(false, false, false, "");
	}
}
